package org.code.generator.controller;

import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.code.generator.entity.ClassInfo;
import org.code.generator.util.CodeGeneratorTool;
import org.code.generator.util.FreemarkerTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * spring boot code generator
 *
 * @author zhengk/moshow
 */
@Controller
@Slf4j
public class IndexController {

    @Autowired
    private FreemarkerTool freemarkerTool;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @PersistenceContext //注入的是实体管理器,执行持久化
    private EntityManager entityManager;

    Map<String, String> result = new HashMap<String, String>();
    Map<String, String> resultFileName = new HashMap<String, String>();
    Map<String, String> resultFilePath = new HashMap<String, String>();

    public static final String author = "zuo lang @";
    public static final String packageName = "com.blog";
    public static final List<String> tableNamePre = Arrays.asList("pub","blog","");

    public static final String projectPath = "/Users/ttylang/gitee/blog/blog-reactive/src/main/java/";

    //文件保存路径 = projectPath + packageName + moduleName

    public static final String entity = "/entity/";
    public static final String controller = "/controller/";
    public static final String repository = "/repository/";

    public static final String ddlSQL = "CREATE TABLE `userinfo` (\n" +
            "  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n" +
            "  `username` varchar(255) NOT NULL COMMENT '用户名',\n" +
            "  `addtime` datetime NOT NULL COMMENT '创建时间',\n" +
            "   PRIMARY KEY (`user_id`)\n" +
            ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息'";

    @RequestMapping("/")
    public String index(ModelMap map) {
        String sql = "show tables";
        List<String> tables = entityManager.createNativeQuery(sql).getResultList();
        map.addAttribute("author", author );
        map.addAttribute("package", packageName);
        map.addAttribute("tables", tables);
        map.addAttribute("ddlSQL",ddlSQL);
        map.addAttribute("tableNamePre", tableNamePre);
        return "index";
    }

    @RequestMapping("/genCode")
    @ResponseBody
    public ResponseEntity<Map<String, String>> codeGenerate(String tableSql, @RequestParam(required = false) String tableName,
                                                            @RequestParam(required = false) String packageName,
                                                            @RequestParam(required = false) String authorName,
                                                            @RequestParam(required = false) String tableNamePre) {
        try {
            if (StringUtils.isNotEmpty(tableName)) {
                Object[] map = (Object[]) entityManager.createNativeQuery("show create table " + tableName).getSingleResult();
                tableSql = map[1].toString();
                log.info("tableName：{}", tableName);
            }

            // parse table
            ClassInfo classInfo = CodeGeneratorTool.processTableIntoClassInfo(tableSql,tableNamePre);


            // code genarete
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("classInfo", classInfo);
            params.put("authorName", authorName);
            params.put("packageName", packageName);
            params.put("returnUtil", "");

            // result
            result.clear();
            resultFilePath.clear();
            resultFileName.clear();

            result.put("className", classInfo.getClassName());

            //UI
            result.put("swagger-ui", freemarkerTool.processString("code-generator/ui/swagger-ui.ftl", params));
            result.put("element-ui", freemarkerTool.processString("code-generator/ui/element-ui.ftl", params));
            result.put("bootstrap-ui", freemarkerTool.processString("code-generator/ui/bootstrap-ui.ftl", params));
            resultFileName.put("swagger-ui", "swagger.html");
            resultFileName.put("element-ui", "element.html");
            resultFileName.put("bootstrap-ui", "bootstrap.html");
            resultFilePath.put("swagger-ui", "html");
            resultFilePath.put("element-ui", "html");
            resultFilePath.put("bootstrap-ui", "html");

            //mybatis old
            result.put("controller", freemarkerTool.processString("code-generator/mybatis/controller.ftl", params));
            result.put("service", freemarkerTool.processString("code-generator/mybatis/service.ftl", params));
            result.put("service_impl", freemarkerTool.processString("code-generator/mybatis/service_impl.ftl", params));
            result.put("mapper", freemarkerTool.processString("code-generator/mybatis/mapper.ftl", params));
            result.put("mybatis", freemarkerTool.processString("code-generator/mybatis/mybatis.ftl", params));
            result.put("model", freemarkerTool.processString("code-generator/mybatis/model.ftl", params));

            resultFileName.put("controller", classInfo.getClassName()+"Controller.java");
            resultFileName.put("service", classInfo.getClassName()+"Service.java");
            resultFileName.put("service_impl", classInfo.getClassName()+"ServiceImpl.java");
            resultFileName.put("mapper", classInfo.getClassName()+"Mapper.java");
            resultFileName.put("mybatis", classInfo.getClassName()+"Mapper.xml");
            resultFileName.put("model", classInfo.getClassName()+".java");

            resultFilePath.put("controller", "controller");
            resultFilePath.put("service", "service");
            resultFilePath.put("service_impl", "service/impl");
            resultFilePath.put("mapper", "mapper");
            resultFilePath.put("mybatis", "res");
            resultFilePath.put("model", "entity");


            //jpa
            result.put("entity", freemarkerTool.processString("code-generator/jpa/entity.ftl", params));
            result.put("repository", freemarkerTool.processString("code-generator/jpa/repository.ftl", params));
            result.put("jpacontroller", freemarkerTool.processString("code-generator/jpa/jpacontroller.ftl", params));

            resultFileName.put("entity", classInfo.getClassName()+".java");
            resultFileName.put("repository", classInfo.getClassName()+"Repository.java");
            resultFileName.put("jpacontroller", classInfo.getClassName()+"Controller.java");

            resultFilePath.put("entity", "entity");
            resultFilePath.put("repository", "repository");
            resultFilePath.put("jpacontroller", "controller");

            //jdbc template
            result.put("jtdao", freemarkerTool.processString("code-generator/jdbc-template/jtdao.ftl", params));
            result.put("jtdaoimpl", freemarkerTool.processString("code-generator/jdbc-template/jtdaoimpl.ftl", params));

            resultFileName.put("jtdao", classInfo.getClassName()+"Dao.java");
            resultFileName.put("jtdaoimpl", classInfo.getClassName()+"DaoImpl.java");

            resultFilePath.put("jtdao", "dao");
            resultFilePath.put("jtdaoimpl", "dao/impl");

            //beetsql
            result.put("beetlmd", freemarkerTool.processString("code-generator/beetlsql/beetlmd.ftl", params));
            result.put("beetlentity", freemarkerTool.processString("code-generator/beetlsql/beetlentity.ftl", params));
            result.put("beetlentitydto", freemarkerTool.processString("code-generator/beetlsql/beetlentitydto.ftl", params));
            result.put("beetlcontroller", freemarkerTool.processString("code-generator/beetlsql/beetlcontroller.ftl", params));

            resultFileName.put("beetlmd",  classInfo.getClassName()+".md");
            resultFileName.put("beetlentity",  classInfo.getClassName()+".java");
            resultFileName.put("beetlentitydto",  classInfo.getClassName()+"DTO.java");
            resultFileName.put("beetlcontroller",  classInfo.getClassName()+"Controller.java");

            resultFilePath.put("beetlmd",  "md");
            resultFilePath.put("beetlentity",  "entity");
            resultFilePath.put("beetlentitydto",  "dto");
            resultFilePath.put("beetlcontroller",  "controller");

            //mybatis plus
            result.put("pluscontroller", freemarkerTool.processString("code-generator/mybatis-plus/pluscontroller.ftl", params));
            result.put("plusmapper", freemarkerTool.processString("code-generator/mybatis-plus/plusmapper.ftl", params));

            resultFileName.put("pluscontroller", classInfo.getClassName()+"Controller.java");
            resultFileName.put("plusmapper", classInfo.getClassName()+"Mapper.java");

            resultFilePath.put("pluscontroller", "controller");
            resultFilePath.put("plusmapper", "mapper");

            //jpa mongodb reactive

            result.put("mongo_document", freemarkerTool.processString("code-generator/jpa-mongodb-reactive/entity.ftl", params));
            result.put("mongo_reposititory", freemarkerTool.processString("code-generator/jpa-mongodb-reactive/repository.ftl", params));
            result.put("mongo_controller", freemarkerTool.processString("code-generator/jpa-mongodb-reactive/jpacontroller.ftl", params));

            resultFileName.put("mongo_document",  classInfo.getClassName()+".java");
            resultFileName.put("mongo_reposititory",  classInfo.getClassName()+"ReactiveRepository.java");
            resultFileName.put("mongo_controller",  classInfo.getClassName()+"Controller.java");

            resultFilePath.put("mongo_document",  "entity");
            resultFilePath.put("mongo_reposititory",  "repository");
            resultFilePath.put("mongo_controller",  "controller");


            //html ant-design
            result.put("base-list", freemarkerTool.processString("code-generator/ant-design/table-list.ftl", params));
            result.put("service-api", freemarkerTool.processString("code-generator/ant-design/service.ftl", params));
            result.put("models", freemarkerTool.processString("code-generator/ant-design/models.ftl", params));

            resultFileName.put("base-list", classInfo.getClassName()+"-BaseList.js");
            resultFileName.put("service-api", classInfo.getClassName().toLowerCase()+"-api.js");
            resultFileName.put("models", classInfo.getClassName().toLowerCase()+"-models.js");

            resultFilePath.put("base-list", "controller");
            resultFilePath.put("service-api", "mapper");
            resultFilePath.put("models", "mapper");

            // 计算,生成代码行数
            int lineNum = 0;
            for (Map.Entry<String, String> item : result.entrySet()) {
                if (item.getValue() != null) {
                    lineNum += StringUtils.countMatches(item.getValue(), "\n");
                }
            }
            log.info("生成代码行数：{}", lineNum);
            //测试环境可自行开启
            return ResponseEntity.ok(result);
        } catch (IOException | TemplateException e) {
        	e.printStackTrace();
        }
        return null;
    }

    @RequestMapping("/showCode")
    public String showCode(@RequestParam String code, ModelMap map) {
        log.info(code);
        map.addAttribute("code", result.get(code));
        map.addAttribute("path", projectPath
                + packageName.replaceAll("\\.","/")
                + "/"+resultFilePath.getOrDefault(code,"")
                + "/");
        map.addAttribute("fileName", resultFileName.get(code));

        return "code";
    }

    @RequestMapping("/createSingleFile")
    public ResponseEntity<?> createSingleFile(@RequestParam String code, @RequestParam String filePath, @RequestParam String fileName) {
        //创建目录
        File file = new File(filePath);
        if (!file.exists()){
            file.mkdirs();
        }

        try {
            FileOutputStream fos = new FileOutputStream(filePath + fileName);
            fos.write(code.getBytes("UTF-8"));
            fos.close();
            log.info("目录：{}{}代码生成成功",filePath,fileName);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return ResponseEntity.ok().build();
    }

    @RequestMapping("/createFiles")
    public ResponseEntity<?> createFiles(@RequestParam String codeStr) throws Exception {


        String []codes = codeStr.split(",");
        for (String code : codes){
            log.info(code);
            String codeLines = result.get(code);
            String filePath = projectPath + packageName.replaceAll("\\.","/") + "/"+resultFilePath.getOrDefault(code,"") + "/";
            String fileName = resultFileName.get(code);

            File file = new File(filePath);
            if (!file.exists()){
                file.mkdirs();
            }

            FileOutputStream fos = new FileOutputStream(filePath + fileName);
            fos.write(codeLines.getBytes("UTF-8"));
            fos.close();
            log.info("目录：{}{}代码生成成功",filePath,fileName);
        }

        return ResponseEntity.ok().build();
    }

}